#![feature(impl_trait_in_assoc_type)]

use embassy_futures::yield_now;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::zerocopy_channel::{self as channel, Channel};
use embassy_time as _; // prevent symbol _embassy_time_* from removing due to dead code in linking

const N: usize = 2;

#[embassy_executor::main]
async fn main(spawner: embassy_executor::Spawner) {
    let buf = Box::into_raw(Box::new([0; N]) as Box<[_]>);

    let channel = Box::leak(Box::new(Channel::<'static, CriticalSectionRawMutex, _>::new(unsafe { &mut *buf })));
    let (sender, recv) = channel.split();

    spawner.spawn(consumer(recv)).unwrap();
    spawner.spawn(producer(sender)).unwrap(); // tasks start in reverse order
}

type Sender = channel::Sender<'static, CriticalSectionRawMutex, i32>;
type Receiver = channel::Receiver<'static, CriticalSectionRawMutex, i32>;

#[embassy_executor::task]
async fn producer(mut sender: Sender) {
    let mut send = |n| {
        if let Some(val) = sender.try_send() {
            *val = n;
            println!("send {n}");
            sender.send_done();
        } else {
            println!("send failure: {n}"); // back pressure
        }
    };
    for m in 1..10 {
        for n in 0..N {
            send((n + m * 10) as i32);
        }
        yield_now().await;
    }
}

#[embassy_executor::task]
async fn consumer(mut receiver: Receiver) {
    let mut recv = || {
        if let Some(val) = receiver.try_receive() {
            println!("recv {val}");
            receiver.receive_done();
        }
    };
    loop {
        recv();
        yield_now().await;
    }
}
